package rtda

import (
	"gvm/rtda/heap"
	"math"
)

type OperandStack struct {
	size  uint        // 操作数栈深度
	slots []heap.Slot // 操作数的槽  用于存储操作数
}

func newOperandStack(maxStack uint) *OperandStack {
	if maxStack > 0 {
		return &OperandStack{size: 0, slots: make([]heap.Slot, maxStack)}
	}
	return nil
}

func (self *OperandStack) PushInt(val int32) {
	self.slots[self.size].SetNum(val)
	self.size++
}

func (self *OperandStack) PopInt() int32 {
	self.size--
	return self.slots[self.size].GetNum()
}

func (self *OperandStack) PushFloat(val float32) {
	bits := math.Float32bits(val)
	self.slots[self.size].SetNum(int32(bits))
	self.size++
}

func (self *OperandStack) PopFloat() float32 {
	self.size--
	bits := uint32(self.slots[self.size].GetNum())
	return math.Float32frombits(bits)
}

func (self *OperandStack) PushLong(val int64) {
	self.slots[self.size].SetNum(int32(val))
	self.size++
	self.slots[self.size].SetNum(int32(val >> 32))
	self.size++
}

func (self *OperandStack) PopLong() int64 {
	self.size -= 2
	low := uint32(self.slots[self.size].GetNum())
	high := uint32(self.slots[self.size+1].GetNum())
	return int64(high)<<32 | int64(low)
}

func (self *OperandStack) PushDouble(val float64) {
	bits := math.Float64bits(val)
	self.PushLong(int64(bits))
}

func (self *OperandStack) PopDouble() float64 {
	bits := uint64(self.PopLong())
	return math.Float64frombits(bits)
}

func (self *OperandStack) PushRef(ref *heap.Object) {
	self.slots[self.size].SetRef(ref)
	self.size++
}

func (os *OperandStack) PushSlot(slot heap.Slot) {
	os.slots[os.size] = slot
	os.size++
}
func (os *OperandStack) PopSlot() heap.Slot {
	os.size--
	return os.slots[os.size]
}
func (os *OperandStack) PushBoolean(b bool) {
	flag := 0
	if b {
		flag = 1
	}
	os.slots[os.size].SetNum(int32(flag))
	os.size++
}
func (os *OperandStack) PopBoolean() bool {
	flag := true
	os.size--
	if os.slots[os.size].GetNum() == 0 {
		flag = false
	}
	return flag
}

func (self *OperandStack) GetRefFromTop(n uint) *heap.Object {
	return self.slots[self.size-1-n].GetRef()
}

func (self *OperandStack) Clear() {
	self.size = 0
	for i := range self.slots {
		self.slots[i].SetRef(nil)
	}
}

func (self *OperandStack) PopRef() *heap.Object {
	self.size--
	r := self.slots[self.size].GetRef()
	self.slots[self.size].SetRef(nil)
	return r
}

func NewOperandStack(maxStack uint) *OperandStack {
	return newOperandStack(maxStack)
}
